/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controladoras.negocio;
import comandos.Up.CmdUpVoo;
import comandos.CmdBD;
import comandos.Del.CmdDelAeroporto;
import comandos.Del.CmdDelVoo;
import comandos.Del.CmdDelVooHasAeroporto;
import comandos.Del.CmdDelVooHasReserva;
import comandos.Ins.CmdInsVoo;
import comandos.Ins.CmdInsVooHasAeroporto;
import comandos.Sel.CmdSelAllAeroporto;
import comandos.Sel.CmdSelAllVoo;
import comandos.Sel.CmdSelVoo;
import comandos.Up.CmdUpVooHasAeroporto;
import comandos.Up.CmdUpVooHasReserva;
import erros.ErroAtualizacao;
import erros.ErroPersistencia;
import interfaces.IGerenciaVoo;
import interfaces.IPersistencia;
import entidades.Voo;
import erros.ErroCadastramento;
import erros.ErroRemocao;
import java.util.ArrayList;
import erros.ErroRecuperacao;
import entidades.Cidade;
import comandos.Sel.CmdSelVoohasAeroporto;
import comandos.Up.CmdUpAeroporto;
import entidades.Aeroporto;
/**
 * Controladora de negócio relativa à entidade voo.
 * @author thiagostuckert
 * @author daniel
 */
public class CntrGerenciaVoo implements IGerenciaVoo {

    /**
     * Referência para o singleton da controladora de negócio
     * da entidade voo.
     */
    private static CntrGerenciaVoo ref;
    /**
     * Referência para a controladora de persistência à ser
     * associada a essa controladora.
     */
    private IPersistencia cntrPersistencia;


    /**
     * Instancia o singleton da controladora de negócio
     * da entidade voo.
     * @return Retorna a referência para o singleton.
     */
    public static CntrGerenciaVoo instanciar() {
        if (ref == null) {
            ref = new CntrGerenciaVoo();
        }
        return (ref);
    }

    /**
     * Atualiza um voo no banco de dados.
     * @param voo Voo a ser atualizado.
     * @param vooNovo Voo contendo os novos atributos.
     * @throws ErroAtualizacao Lança exceção de atualização
     * em caso de falha.
     */
    @Override
    public void atualizarVoo(final Voo voo,final Voo vooNovo)
            throws ErroAtualizacao{

        Aeroporto aeroPartidaNovo = voo.getAeroportoPartida();
        Aeroporto aeroPartidaVelho =   voo.getAeroportoPartida();
        Aeroporto aeroChegadaNovo =  voo.getAeroportoChegada();
        Aeroporto aeroChegadaVelho =voo.getAeroportoChegada();
        /**
         * Recupera os aeroportos
         */
        try {
            int match = 0;
            CmdBD comando = new CmdSelAllAeroporto();
            ArrayList<Aeroporto> lista = (ArrayList<Aeroporto>)
                    cntrPersistencia.executar(comando);
            for(int i = 0 ; i< lista.size() ; i++) {
                Aeroporto aero;
                aero = lista.get(i);
                if(aero.getCodigoAeroporto()
                        .equals(vooNovo.getAeroportoChegada().
                        getCodigoAeroporto())) {
                    aeroChegadaNovo = aero;
                    match++;
                    break;
                }
            }

            for(int i = 0 ; i< lista.size() ; i++) {
                Aeroporto aero;
                aero = lista.get(i);
                if(aero.getCodigoAeroporto()
                        .equals(vooNovo.getAeroportoPartida().
                        getCodigoAeroporto())) {
                    aeroPartidaNovo = aeroPartidaNovo;
                    match++;
                    break;
                }
            }
            if(match != 2) {
                throw new ErroPersistencia();
            }

        } catch (ErroPersistencia e) {
            throw new ErroAtualizacao("Aeroporto não disponível");
        }
        /**
         * Atualiza os vôos.
         */
        try{
            CmdBD comando = new CmdUpVoo(voo,vooNovo);
            cntrPersistencia.executar(comando);
            comando = new CmdUpVooHasReserva(voo, vooNovo);
            cntrPersistencia.executar(comando);
            comando = new CmdUpVooHasAeroporto(voo, vooNovo);
            cntrPersistencia.executar(comando);
            comando = new CmdUpAeroporto(aeroPartidaVelho,
                    aeroPartidaNovo);
            cntrPersistencia.executar(comando);
            comando = new CmdUpAeroporto(aeroChegadaVelho,
                    aeroChegadaNovo);
            cntrPersistencia.executar(comando);
            comando = new CmdUpVooHasAeroporto(aeroChegadaVelho,
                    aeroChegadaNovo);
            cntrPersistencia.executar(comando);
            comando = new CmdUpVooHasAeroporto(aeroPartidaVelho,
                    aeroPartidaNovo);
            cntrPersistencia.executar(comando);
        } catch (ErroPersistencia e) {
            throw new ErroAtualizacao("Nao foi possivel atualizar o voo");
        }
    }

    /**
     * Deleta um voo do banco de dados.
     * @param voo Voo a ser deletado
     * @throws ErroRemocao Lança exceção de remoção em caso de falha.
     */
    @Override
    public void deletarVoo(Voo voo) throws ErroRemocao {
        try{
            CmdBD comando = new CmdDelVoo(voo);
            cntrPersistencia.executar(comando);
            comando = new CmdDelVooHasAeroporto(voo);
            cntrPersistencia.executar(comando);
            comando = new CmdDelVooHasReserva(voo);
            cntrPersistencia.executar(comando);
        } catch(ErroPersistencia e){
            throw new ErroRemocao("Nao foi possivel remover o voo");
        }
    }

    /**
     * Cadastra um voo no banco de dados.
     * @param voo Voo a ser cadastrado.
     * @throws ErroCadastramento Lança um erro de
     * cadastramento em caso de falha.
     */
    @Override
    public void cadastrarVoo(Voo voo) throws ErroCadastramento {

        Aeroporto aeroPartida = null;
        Aeroporto aeroChegada = null;
        int match = 0;
        /** Verifica se existem os aeroportos **/
        try {
            CmdBD comando = new CmdSelAllAeroporto();
            ArrayList<Aeroporto> lista =
                   (ArrayList)cntrPersistencia.executar(comando);
            for(int i=0;i<lista.size();i++){
               Aeroporto aero = lista.get(i);
               if(aero.getCodigoAeroporto().equals
                       (voo.getAeroportoPartida().getCodigoAeroporto())){
                   match++;
                   aeroPartida = voo.getAeroportoPartida();
                   break;
               }
            }

            for(int i=0;i<lista.size();i++){
               Aeroporto aero = lista.get(i);
               if(aero.getCodigoAeroporto().equals
                       (voo.getAeroportoChegada().getCodigoAeroporto())){
                   match++;
                   aeroChegada = voo.getAeroportoChegada();
                   break;
               }
            }
            if(match!=2) {
                throw new ErroPersistencia("Aeroporto de Partida ou" +
                        " de Chegada" +
                        "não cadastrado no banco");
            }
        } catch (ErroPersistencia e) {
            throw new ErroCadastramento("Não foi possivel cadastrar o voo," +
                    "aeroportos não existentes.");
        }
        /** cadastra o voo de fato **/
        try{
            CmdBD comando = new CmdInsVoo(voo);
            cntrPersistencia.executar(comando);
            comando = new CmdInsVooHasAeroporto(voo, aeroPartida, true);
            cntrPersistencia.executar(comando);
            comando = new CmdInsVooHasAeroporto(voo, aeroChegada, false);
            cntrPersistencia.executar(comando);
        } catch (ErroPersistencia e) {
            throw  new ErroCadastramento("Nao foi possivel cadastrar o voo");
        }
    }
    /**
     * Seta a controladora de persistência associada com esta controladora.
     * @param cntrPersistencia
     */
    public void setCntrPersistencia(IPersistencia cntrPersistencia) {
        this.cntrPersistencia = cntrPersistencia;
    }

    /**
     * Recupera os voos do banco de dados.
     * @return lista lista de voos armazenados no banco.
     * @throws ErroRecuperacao
     */
    @Override
    public ArrayList<Voo> recuperarVoos() throws ErroRecuperacao{
        ArrayList<Voo> listaVoos = new ArrayList();
        try {
            CmdBD comando = new CmdSelAllVoo();
            listaVoos = (ArrayList<Voo>) cntrPersistencia.executar(comando);
            for(int i = 0; i < listaVoos.size(); i++) {
                Voo voo = listaVoos.get(i);
                comando = new CmdSelVoohasAeroporto(voo,true);
                ArrayList lista_auxiliar =
                        (ArrayList) cntrPersistencia.executar(comando);
                Cidade cidadeOrigem = (Cidade)lista_auxiliar.get(0);
                Aeroporto aeroportoPartida = (Aeroporto)lista_auxiliar.get(1);

                comando = new CmdSelVoohasAeroporto(voo,false);
                lista_auxiliar =
                        (ArrayList) cntrPersistencia.executar(comando);
                Cidade cidadeDestino = (Cidade) lista_auxiliar.get(0);
                Aeroporto aeroportoChegada = (Aeroporto) lista_auxiliar.get(1);
                voo.setAeroportoChegada(aeroportoChegada);
                voo.setAeroportoPartida(aeroportoPartida);
                voo.setCidadeDestino(cidadeDestino);
                voo.setCidadeOrigem(cidadeOrigem);
            }
        } catch (ErroPersistencia e) {
            throw new ErroRecuperacao("Não foi possível recuperar os voos " +
                    "do banco");
        }
        return listaVoos;
    }

    /**
     * Recupera voos do banco de dados associados a uma cidade de origem,
     * uma de destino e uma data.
     * @param cidadeOrigem Cidade de origem dos voos recuperados.
     * @param cidadeDestino Cidade de destino dos voos recuperados.
     * @param dataPartida Data dos voos a serem recuperados.
     * @return Lista de voos que partiram da cidade de origem para uma cidade
     * de destino em uma determinada data.
     * @throws ErroRecuperacao Lança erro de recuperação em caso de falha.
     */
    @Override
    public ArrayList<Voo> recuperarVoos(Cidade cidadeOrigem,
            Cidade cidadeDestino,String dataPartida) throws ErroRecuperacao{

        try {
            CmdBD comando = new CmdSelVoo(cidadeOrigem, cidadeDestino
                    , dataPartida);
            ArrayList<Voo> listaVoos =
                    (ArrayList<Voo>) cntrPersistencia.executar(comando);
            for(int i = 0; i < listaVoos.size(); i++) {
                Voo voo = listaVoos.get(i);
                comando = new CmdSelVoohasAeroporto(voo,true);
                ArrayList lista_auxiliar =
                        (ArrayList) cntrPersistencia.executar(comando);
                Aeroporto aeroportoPartida = (Aeroporto)lista_auxiliar.get(1);

                comando = new CmdSelVoohasAeroporto(voo,false);
                lista_auxiliar =
                        (ArrayList) cntrPersistencia.executar(comando);
                Aeroporto aeroportoChegada = (Aeroporto) lista_auxiliar.get(1);
                voo.setAeroportoChegada(aeroportoChegada);
                voo.setAeroportoPartida(aeroportoPartida);
                voo.setCidadeDestino(cidadeDestino);
                voo.setCidadeOrigem(cidadeOrigem);
            }
            return listaVoos;
        } catch (ErroPersistencia e) {
            throw new ErroRecuperacao("Não foi possível recuperar os vôos");
        }
    }

    /**
     * Recupera um voo atraves do codigo do voo.
     * @param voo codigo do voo a ser recuperado.
     * @return voo voo armazenado no banco.
     * @throws ErroRecuperacao lança exceção caso a ação
     * não obtenha sucesso.
     */
    @Override
    public Voo recuperarVoo(Voo voo) throws ErroRecuperacao {
        try {
            CmdBD comando = new CmdSelVoo(voo);
            ArrayList<Voo> listaVoos =
                    (ArrayList<Voo>) cntrPersistencia.executar(comando);
            if(listaVoos.size() == 0) {
                throw new ErroRecuperacao("Voo não existe no banco.");
            }
            comando = new CmdSelVoohasAeroporto(listaVoos.get(0),true);
            ArrayList lista_auxiliar =
                        (ArrayList) cntrPersistencia.executar(comando);
            Cidade cidadeOrigem = (Cidade)lista_auxiliar.get(0);
            Aeroporto aeroportoPartida = (Aeroporto)lista_auxiliar.get(1);

            comando = new CmdSelVoohasAeroporto(listaVoos.get(0),false);
            lista_auxiliar =
                        (ArrayList) cntrPersistencia.executar(comando);
            Cidade cidadeDestino = (Cidade)lista_auxiliar.get(0);
            Aeroporto aeroportoChegada = (Aeroporto) lista_auxiliar.get(1);
                listaVoos.get(0).setAeroportoChegada(aeroportoChegada);
                listaVoos.get(0).setAeroportoPartida(aeroportoPartida);
                listaVoos.get(0).setCidadeDestino(cidadeDestino);
                listaVoos.get(0).setCidadeOrigem(cidadeOrigem);
            return listaVoos.get(0);
        } catch (ErroPersistencia e) {
            throw new ErroRecuperacao("Não foi possível recuperar o vôo");
        }
    }
}
